package com.mo.lib.utils.res

import android.R
import android.content.res.ColorStateList
import android.graphics.Color
import android.util.TypedValue
import androidx.annotation.ColorInt
import androidx.annotation.FloatRange
import androidx.core.graphics.ColorUtils
import com.dylanc.longan.application
import java.util.ArrayList

/**
 * @ author：mo
 * @ data：2019/2/13:10:17
 * @ 功能：颜色选择器 构建辅助类
 */
class ColorSelectorBuilder {
    private val mStates: ArrayList<IntArray> = ArrayList()
    private val mColors: ArrayList<Int> = ArrayList()

    /**设置选择状态下的颜色       color 颜色值*/
    fun setSelectedColor(color: Int)=addState(intArrayOf(R.attr.state_selected),color)

    /**设置可用状态下的颜色       color 颜色值*/
    fun setEnabledColor(color: Int)=addState(intArrayOf(R.attr.state_enabled),color)

    /**设置按下状态下的颜色       color 颜色值*/
    fun setPressedColor(color: Int)=addState(intArrayOf(R.attr.state_pressed),color)

    /**设置其余状态下的颜色       color 颜色值*/
    fun setOtherStateColor(color: Int)=addState(intArrayOf(),color)

    /**设置指定状态下的颜色       color 颜色值*/
    fun addState(stateSet: IntArray, color: Int): ColorSelectorBuilder {
        mStates.add(stateSet)
        mColors.add(color)
        return this
    }

    /** 获取构建好的颜色选择器*/
    fun getSelector(): ColorStateList {
        val states = mStates.toTypedArray()
        val colors: IntArray = toIntArray(mColors)
        return ColorStateList(states, colors)
    }
    private fun toIntArray(list: List<Int>): IntArray {
        val array = IntArray(list.size)
        for (i in array.indices) {
            array[i] = list[i]
        }
        return array
    }
}


/** 混合颜色*/
fun compositeColors(@ColorInt foreground: Int, @ColorInt background: Int)= ColorUtils.compositeColors(foreground, background)

/**
 * 设置颜色的alpha值
 *
 * @param color    需要被设置的颜色值
 * @param alpha    取值为[0,1]，0表示全透明，1表示不透明
 * @param override 覆盖原本的 alpha
 * @return 返回改变了 alpha 值的颜色值
 */
fun getColor(@ColorInt color: Int, @FloatRange(from = 0.0, to = 1.0) alpha: Float, override: Boolean)= color and 0x00ffffff or (alpha * ( if (override) 0xff else color shr 24 and 0xff)).toInt() shl 24

/**
 * 覆盖颜色, 在背景颜色上覆盖一层颜色(有透明度)后得出的混合颜色
 *
 * 注意: 覆盖的颜色需要有一定的透明度, 如果覆盖的颜色不透明, 得到的颜色为覆盖的颜色
 *
 * @param baseColor  基础颜色(背景颜色)
 * @param coverColor 覆盖颜色(前景颜色)
 * @return
 */
fun coverColor(@ColorInt baseColor: Int, @ColorInt coverColor: Int): Int {
    val fgAlpha = Color.alpha(coverColor)
    val bgAlpha = Color.alpha(baseColor)
    val a = blendColorNormalFormula(255, bgAlpha, fgAlpha, bgAlpha)
    val r = blendColorNormalFormula(Color.red(coverColor), Color.red(baseColor), fgAlpha, bgAlpha)
    val g = blendColorNormalFormula(Color.green(coverColor), Color.green(baseColor), fgAlpha, bgAlpha)
    val b = blendColorNormalFormula(Color.blue(coverColor), Color.blue(baseColor), fgAlpha, bgAlpha)
    return Color.argb(a, r, g, b)
}

/**
 * 抽取颜色 (覆盖颜色的相反操作), 用于猜测何种颜色覆盖上需要抽取的颜色会得出基准颜色
 *
 * 注意:
 * <br></br>1.抽取的颜色需要有一定的透明度
 * <br></br>2.可能无法准确得出抽取后的颜色 (某个颜色范围内覆盖上需要抽取的颜色都可以得到基准颜色, 默认取颜色值最低的数值)
 * <br></br>3.可能无法得出抽取后的颜色 (任何颜色覆盖上需要抽取的颜色都无法得到基准颜色, 会报错)
 *
 * @param baseColor      基础颜色
 * @param extractedColor 需要抽取掉的颜色
 * @return 抽取后得到的颜色
 */
fun extractColor(@ColorInt baseColor: Int, @ColorInt extractedColor: Int): Int {
    val fgAlpha = Color.alpha(extractedColor)
    val mixedAlpha = Color.alpha(baseColor)
    val bgAlpha = Math.round(Math.sqrt(((mixedAlpha - fgAlpha) / (255 - fgAlpha)).toDouble()) * 255).toInt()
    val bgRed = ((Color.red(baseColor) * 255 - Color.red(extractedColor) * fgAlpha) * 255f / ((255 - fgAlpha) * bgAlpha)).toInt()
    val bgGreed = ((Color.green(baseColor) * 255 - Color.green(extractedColor) * fgAlpha) * 255f / ((255 - fgAlpha) * bgAlpha)).toInt()
    val bgBlue = ((Color.blue(baseColor) * 255 - Color.blue(extractedColor) * fgAlpha) * 255f / ((255 - fgAlpha) * bgAlpha)).toInt()
    return Color.argb(bgAlpha, bgRed, bgGreed, bgBlue)
}

/** 获取主题颜色*/
fun getColorPrimary(): Int {
    val typedValue = TypedValue()
    application.theme.resolveAttribute(R.attr.colorPrimary, typedValue, true)
    return typedValue.data
}

/**将 color 颜色值转换为十六进制字符串 */
fun getColorString(color: Int)=String.format("#%08X", color)

/**
 * 颜色混合模式中正常模式的计算公式
 * 公式: 最终色 = 基色 * a% + 混合色 * (1 - a%)
 */
private fun blendColorNormalFormula(fgArgb: Int, bgArgb: Int, fgAlpha: Int, bgAlpha: Int): Int {
    val mix = (fgArgb * fgAlpha / 255f + (1 - fgAlpha / 255f) * bgArgb * bgAlpha / 255f).toInt()
    return if (mix > 255) 255 else mix
}

/**
 * 根据比例，在两个color值之间计算出一个color值
 * **注意该方法是ARGB通道分开计算比例的**
 *
 * @param fromColor 开始的color值
 * @param toColor   最终的color值
 * @param fraction  比例，取值为[0,1]，为0时返回 fromColor， 为1时返回 toColor
 * @return 计算出的color值
 */
fun computeColor(@ColorInt fromColor: Int, @ColorInt toColor: Int, fraction: Float): Int {
    var fraction = fraction
    fraction = Math.max(Math.min(fraction, 1f), 0f)
    val minColorA = Color.alpha(fromColor)
    val maxColorA = Color.alpha(toColor)
    val resultA = ((maxColorA - minColorA) * fraction).toInt() + minColorA
    val minColorR = Color.red(fromColor)
    val maxColorR = Color.red(toColor)
    val resultR = ((maxColorR - minColorR) * fraction).toInt() + minColorR
    val minColorG = Color.green(fromColor)
    val maxColorG = Color.green(toColor)
    val resultG = ((maxColorG - minColorG) * fraction).toInt() + minColorG
    val minColorB = Color.blue(fromColor)
    val maxColorB = Color.blue(toColor)
    val resultB = ((maxColorB - minColorB) * fraction).toInt() + minColorB
    return Color.argb(resultA, resultR, resultG, resultB)
}
